package com.example.aop.aspectj;

import com.example.aop.service.Log;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;

@Aspect
@Component
public class UserAspectj {

    private static final Logger logger = LoggerFactory.getLogger(UserAspectj.class);

    /**
     * execution  方法级别
     */
    @Pointcut("execution(* com.example.aop.service.UserService.*(..))")
    public void userPointcut(){}

    /**
     * within 类级别=UserService所有方法
     */
    @Pointcut("within(com.example.aop.service.impl.UserServiceImpl)")
    public void withinPointcut(){}

    /**
     * annotation 作用于注解
     * @param log
     */
    @Pointcut("@annotation(log)")
    public void annotationPointcut(Log log){}

    /**
     * this:作用于接口类
     */
    @Pointcut("this(com.example.aop.service.UserService)")
    public void thisPointcut(){}

    /**
     * target:作用于目标对象
     * 类：com.example.aop.service.impl.UserServiceImpl
     * 接口：com.example.aop.service.UserService
     */
    @Pointcut("target(com.example.aop.service.impl.UserServiceImpl)")
    public void targetPointcut(){}

    /**
     * args:只作用于方法参数 - 切点表达式过于宽泛
     * 由于String类型作用域比较广，所以必须限制作用域的目标对象
     */
    @Pointcut("args(java.lang.String)")
    public void stringArg() {}

    /**
     * args:只作用于方法参数 - 切点表达式过于宽泛
     * 自定义参数类使用时，也必须要限制作用域的目标对象
     */
    @Pointcut("args(com.example.aop.bo.UserBO)")
    public void  userBOArg() {}

//    @After("targetPointcut() && stringArg()")
    @After("targetPointcut() && userBOArg()")
    public void after(){
        logger.info("【after】后置通知");
    }

    @Before("userPointcut() && withinPointcut() && annotationPointcut(log)")
    public void beforePointcut(JoinPoint joinPoint, Log log){
        // 注解信息
        logger.info(log.value());
        logger.info("抽取切点表达式");

    }

}
